#include "tcpclient.hpp"
#include <iostream>
using namespace std;

/**
 * @brief Construct a new Tcp Client:: Tcp Client object
 *
 * @param ip
 * @param port
 */
TcpClient::TcpClient(string ip, uint16_t port)
{
    // 初始化信息
    this->ip = ip;
    this->port = port;
    sock = socket(AF_INET, SOCK_STREAM, 0); // 创建socket
    if (sock < 0)
    {
        cerr << "client socket fail" << endl;
        std::exit(-1);
    }
}
/**
 * @brief Destroy the Tcp Client:: Tcp Client object
 *
 */
TcpClient::~TcpClient()
{
    if (sock >= 0)
    {
        close(sock);
    }
}
/**
 * @brief client主线程-用来读取client的需求指令
 *
 */
void TcpClient::start()
{
    // 填写server端信息
    struct sockaddr_in server;
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip.c_str());
    // 建立链接
    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0)
    {
        cerr << "client connect fail" << endl;
        close(sock);
        std::exit(-1);
    }
    // 初始化通信信号
    sem_init(&rwsem, 0, 0);
    // 启动读线程
    thread readTask(readTaskHandler, this);
    readTask.detach();
    // main线程用于接收用户输入，负责发送数据
    while (true)
    {
        // 显示首页面菜单 登录、注册、退出
        cout << "========================" << endl;
        cout << "1. login" << endl;
        cout << "2. register" << endl;
        cout << "3. quit" << endl;
        cout << "========================" << endl;
        cout << "choice:";

        int choice = 0;
        while (!(cin >> choice)) // 解决错误输入
        {
            cin.clear();
            while (cin.get() != '\n')
                continue;
            cout << "plese input a number:";
        }
        switch (choice)
        {
        case 1: // login业务
        {
            int id = 0;
            char pwd[50] = {0};
            cout << "userid:";
            cin >> id;
            cin.get(); // 读掉缓冲区残留的回车
            cout << "userpassword:";
            cin.getline(pwd, 50);

            json js;
            js["msgid"] = LOGIN_MSG;
            js["id"] = id;
            js["password"] = pwd;
            string request = js.dump();

            loginstate = false; // 还没有登录成功

            int len = send(sock, request.c_str(), strlen(request.c_str()) + 1, 0);
            if (len == -1)
            {
                cerr << "send login msg error:" << request << endl;
            }

            sem_wait(&rwsem); // 等待读线程获取响应

            if (loginstate)
            {
                // 进入聊天主菜单页面
                client.mainMenu(sock);
            }
        }
        break;
        case 2: // register业务
        {
            char name[50] = {0};
            char pwd[50] = {0};
            cout << "username:";
            cin.getline(name, 50);
            cout << "userpassword:";
            cin.getline(pwd, 50);

            json js;
            js["msgid"] = REG_MSG;
            js["name"] = name;
            js["password"] = pwd;
            string request = js.dump();

            int len = send(sock, request.c_str(), strlen(request.c_str()) + 1, 0);
            if (len == -1)
            {
                cerr << "send reg msg error:" << request << endl;
            }

            sem_wait(&rwsem); // 等待读线程获取响应
        }
        break;
        case 3: // quit业务
            close(sock);
            sem_destroy(&rwsem);
            std::exit(0);
        default:
            cerr << "not have the choice!" << endl;
            break;
        }
    }
}
/**
 * @brief 子线程进行读取服务端发送的的数据
 *
 * @param arg
 * @return void*
 */
void *TcpClient::readTaskHandler(void *arg)
{
    TcpClient *tc = (TcpClient *)arg;
    while (true)
    {
        // 接收消息
        char buffer[4096] = {0};
        int len = recv(tc->getSock(), buffer, 4096, 0);
        if (-1 == len || 0 == len)
        {
            close(tc->getSock());
            std::exit(-1);
        }

        // json反序列化
        json js = json::parse(buffer);
        int msgtype = js["msgid"].get<int>();
        if (ONE_CHAT_MSG == msgtype)
        {
            cout << "[" << js["time"].get<string>() << "][FriendId:" << js["id"] << "][" << js["name"].get<string>() << "]"
                 << " said: " << js["msg"].get<string>() << endl;
            continue;
        }

        if (GROUP_CHAT_MSG == msgtype)
        {
            cout << "[" << js["time"].get<string>() << "][GroupId:" << js["groupid"] << "][FriendId:" << js["id"] << "][" << js["name"].get<string>() << "]"
                 << " said: " << js["msg"].get<string>() << endl;
            continue;
        }

        if (REG_MSG_ACK == msgtype)
        {
            if (0 != js["errno"].get<int>()) // 注册失败
            {
                cerr << "name is already exist, register error!" << endl;
            }
            else // 注册成功
            {
                cout << "name register success, userid is " << js["id"]
                     << ", do not forget it!" << endl;
            }
            sem_post(&tc->getSem()); // 通知主线程，登录结果处理完成
            continue;
        }

        if (LOGIN_MSG_ACK == msgtype)
        {
            tc->getLoginState() = tc->getClient().loginResponse(js);
            sem_post(&tc->getSem()); // 通知主线程，登录结果处理完成
            continue;
        }
    }
}
